/*
Copyright (c) 2008 Chagrin Research, LLC

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef _primitives_h
#define _primitives_h

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <values.h>
#include <math.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sys/mman.h>


#define PACKED __attribute__((packed))

extern const double meters_per_nm;

//grid prototypes
typedef struct grid_bounds
{
	double southwest_lat;
	double southwest_lng;
	double northeast_lat;
	double northeast_lng;
} grid_bounds;

typedef struct grid
{
	double* data;
	double max_value;
	int width;
	int height;
	double scale_x;
	double scale_y;
	grid_bounds bounds;
	double utm_southing;
	double utm_westing;
	char zone[16];
} grid;

grid* grid_create(int width_px, int height_px);
void grid_destroy(grid* g);
void grid_set_geometry(grid* g,double lat, double lng, double scale_x /*meters to pixels*/, double scale_y /*meters to pixels*/);
void grid_set_pixel(grid* g,int x, int y, double value);
void grid_set_point(grid* g,double x, double y,double value);
double grid_get_pixel(grid* g,int x, int y);
double grid_get_point(grid* g,double x, double y);
double grid_get_coord(grid* g,double lat, double lng);


const double epsilon;
const double sat_radius;
const double earth_radius;
const double speed_of_light;
const double pi;

typedef struct vector
{
	double x;
	double y;
	double z;
	double mag;
} vector;

/*typedef struct point
{
	double x;
	double y;
	double z;
	double r;
} point;*/

typedef struct bounds
{
	double lng;
	double lat;
	double z;
	double m;
} bounds;

#define MIN_BOUNDS {1000.0,1000.0,0.0,0.0}
#define MAX_BOUNDS {-1000.0,-1000.0,0.0,0.0}

//nexrad
typedef struct radial
{
	unsigned short index_of_first_bin;
	unsigned short number_of_range_bins;
	short i_center_of_sweep;
	short j_center_of_sweep;
	unsigned short scale_factor;
	unsigned short number_of_radials;
} __attribute__((packed)) radial;

typedef struct radial_line
{
	unsigned short number_of_rle;
	unsigned short start_angle;
	unsigned short angle_delta;
	//unsigned short rle[];
} __attribute__((packed)) radial_line;

typedef struct rle
{
	unsigned char color1 : 4; //LSB
	unsigned char run1 : 4;
	unsigned char color0 : 4;
	unsigned char run0 : 4; //MSB
} __attribute__((packed)) rle;

typedef struct raster
{
	unsigned short packet_code2;
	unsigned short packet_code3;
	short i_coordinate_start;
	short j_coordinate_start;
	unsigned short x_scale_int;
	unsigned short x_scale_fractional;
	unsigned short y_scale_int;
	unsigned short y_scale_fractional;
	unsigned short number_of_rows;
	unsigned short packing_descriptor;
} __attribute__((packed)) raster;

typedef struct msg_header_block
{
	unsigned short message_code; //HW 1
	unsigned short julian_date_code;//2
	unsigned int timestamp;//3,4
	unsigned int length;//5,6
	unsigned short source_id;//7
	unsigned short dest_id;//8
	unsigned short number_blocks;//9

	//product_description_block
	short divider;//10
	int latitude;//11,12
	int longitude;//13,14
	short height;//15
	unsigned short product_code;//16
	unsigned short operational_mode;//17
	unsigned short volume_coverage_pattern;//18
	short sequence_number;//19
	unsigned short volume_scan_number;//20
	unsigned short volume_scan_date;//21
	unsigned int volume_scan_start_time;//22,23
	unsigned short product_gen_date;//24
	unsigned int product_gen_time;//25,26
	unsigned short parameter1;//27
	unsigned short parameter2;//28
	unsigned short elevation_number;//29
	unsigned short elevation_angle;//30
	
	unsigned short data_level_threshold[16];//31-46
	
	unsigned short parameter4;//47
	unsigned short parameter5;//48
	unsigned short parameter6;//49
	unsigned short parameter7;//50
	unsigned short parameter8;//51
	unsigned short parameter9;//52
	unsigned short parameter10;//53
	
	unsigned char version;//54
	unsigned char spot_blank;
	unsigned int offset_to_symbology;//55,56
	unsigned int offset_to_graphic;//57,58
	unsigned int offset_to_tabular;//58,59
	
	//product symbology block
	short divider2;
	unsigned short block_id;
	unsigned int block_length;
	unsigned short number_of_layers;
	short layer_divider;
	unsigned int length_data_layer;
	
	unsigned short packet_code;
	union
	{
		radial radial_data;
		raster raster_data;
	};
} __attribute__((packed)) msg_header;

typedef struct bounding_box
{
	bounds south_west;
	bounds north_east;

} bounding_box;

typedef struct rgba8 {unsigned char r; unsigned char g; unsigned char b; unsigned char a;} PACKED rgba8;
grid* get_nexrad_data(char* station, double* station_lat, double* station_lng,bounding_box* b,char* url);
int write_nexrad_png(char* filename,grid* g,void(*translate_levels)(int,int,double*,rgba8*));
void translate_levels(int width,int i,double* grid_data,rgba8* row);


//files.c
typedef struct mapped_file
{
	struct stat stat;
	int fd;
	char* data;
	off_t offset;
	size_t length;
} mapped_file;


mapped_file* mapfile(const char* filename, size_t length);
void unmapfile(mapped_file* f);


#endif
